<?php

abstract class Nina_Controller_Test extends Nina_Controller
{
	protected $subject_controller;
	protected $results = array();

	/**
	 * Constructor
	 * @param string $controller The controller name
	 * @param string $action The action name
	 * @param integer $id The ID
	 */
	public function __construct($controller = 'test', $action, $id) {
		parent::__construct($controller, $action, $id);
	}

	/**
	 * Validate that we have the required controllers
	 * @return boolean
	 */	
	protected function validate() {
		if($this->subject_controller) {
			$test_controller_name = ucfirst($this->getController()) . '_Controller';
			$subject_controller_name = ucfirst($this->subject_controller) . '_Controller';
		
			if(class_exists($test_controller_name) && class_exists($subject_controller_name))
				return true;
			else {
				$this->addMessage($test_controller_name . ' and/or ' . $subject_controller_name . 'cannot be found');
				return false;
			}
		}
		else {
			$this->addMessage('No subject controller defined');
			return false;
		}
	}
	
	/**
	 * Default run test method
	 */	
	public function index() {	
		$this->setTitle('Test');
	
		$this->runTests();
	}
	
	/**
	 * Get the test results
	 * @return array
	 */	
	public function getResults() {
		return $this->results;
	}

	/**
	 * Run the tests
	 */	
	protected function runTests() {
		if($this->validate()) {
			$test_controller_name = ucfirst($this->getController()) . '_Controller';
			$test_controller_methods = get_class_methods($test_controller_name);
			$subject_controller_name = ucfirst($this->subject_controller) . '_Controller';
			$subject_controller_methods = get_class_methods($subject_controller_name);
			
			if(method_exists($this, 'setUp'))
				$this->setUp();

			foreach($test_controller_methods as $action) {
				if(preg_match('/^test\_?[a-zA-Z0-9\-\_]+$/', $action)) {
					$subject_action = lcfirst(preg_replace('/test\_?/', '', $action));
				
					if(in_array($subject_action, $subject_controller_methods)) {

						$test_data = $this->$action();
						
						if(is_array($test_data) && isset($test_data['request']) && isset($test_data['response'])) {
							$json_response = (isset($test_data['json'])) ? $test_data['json'] : true;
							
							$test_response = $this->curlRequest($subject_action, $test_data['request'], $json_response);

							//Check if we're regexing
							if(is_string($test_data['response']) && ($test_data['response']{0} == '/' || $test_data['response']{0} == '^'))
								$success = (preg_match($test_data['response'], $test_response) > 0);
							else
								$success = ($test_response === $test_data['response']);

							$this->results[] = array('success' => $success, 'action' => $action, 'desired_response' => $test_data['response'], 'actual_response' => $test_response);
						}
					}
				}
			}
			
			if(method_exists($this, 'breakDown'))
				$this->breakDown();
		}
	}

	/**
	 * Send a curl request
	 * @param string $action The test action
	 * @param array [$data=array()] The post data
	 * @param boolean [$json_response=true] Decode response data as JSON
	 * @param string|array
	 */	
	protected function curlRequest($action, $data = array(), $json_response = true) {
	
		// Initializing curl
		$ch = curl_init(Nina_Links::getUrlRoot() . '/' . $this->subject_controller . '/' . $action);
		 
		// Configuring curl options
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
		
		$headers = array();
		
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		
		// Getting results
		$response = curl_exec($ch);
		curl_close($ch);

		return $json_response ? (array)json_decode($response) : $response;
	}
}